/** \file    warp.h
  * \brief   Warp YATL::Arr2D-based image.
  * \date    1998-2001
  * \author  Aloudin (Albert) Akhriev
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/imglib/warp.h,v 1.2 2004/12/10 05:10:44 cscom1r4 Exp $
  */

#ifndef _warp_h_
#define _warp_h_

#include "xtd/Arr2D.h"
#include "type.h"
#include "typelib/types.h"

namespace img {

///preimage - function that for each point of current frame associates coordinates of original point on the first frame
///this function changes preimage according to transformation further on one next frame
void warpPreimage(PntArr2f &preimage, const QuadraticForm &qf, 
	float reservedPreimageValue,			///< signals that preimage cant' be found at a point
	const int_point &ref = int_point());	///< reference point of trasformation in preimage

//-------------------------------------------------------------------------------------------------
// Function warpes image according to the specified motion parameters using bilinear interpolation.
//-------------------------------------------------------------------------------------------------
template<class T>
void WarpImage(
  const YATL::Arr2D<T> & source,   // source image
  YATL::Arr2D<T>       & dest,     // warped image
  double         * P,        // parameters of motion source_color(dest_x,dest_y)
  int              nParam)   // number of motion parameters
{
  int W = source.Width();
  int H = source.Height();

  assert(nParam == 8);
  if (!YATL::HasEqualDim(source, dest))
    dest.Resize(W, H);
  std::fill(dest.begin(), dest.end(), T());

  for(int j = 0; j < H; j++)
  {
    for(int i = 0; i < W; i++)
    {
      double u = i + (P[0] + i*P[1] + j*P[2] + (i*i)*P[6] + (i*j)*P[7]);
      double v = j + (P[3] + i*P[4] + j*P[5] + (i*j)*P[6] + (j*j)*P[7]);
      int    x = int(u + 1.0) - 1;
      int    y = int(v + 1.0) - 1;

      if (x < 0 || y < 0 || (x+1) >= W || (y+1) >= H)
      {
        dest.At(i,j) = T();
        continue;
      }

                                       // Pixels location:
      float dx = float(u - x);         // p3 p2          c3 c2
      float dy = float(v - y);         // p0 p1   <--->  c0 c1
      float C2 = dx * dy;
      float C1 = dx - C2;
      float C3 = dy - C2;
      float C0 = 1.0f - dy - C1;

      dest.At(i,j) = source.At(x,y)*C0 + source.At(x+1,y)*C1 + source.At(x+1,y+1)*C2 + source.At(x,y+1)*C3;
    }
  }
}

} //namespace img

#endif //_warp_h_
